from decimal import Decimal
from django.utils import timezone
from rest_framework import serializers
from django_redis import get_redis_connection
from django.db import transaction

from goods.models import SKU
from .models import OrderInfo, OrderGoods


class CommitOrderSerializer(serializers.ModelSerializer):
    """
    下单数据序列化器
    """

    class Meta:
        model = OrderInfo
        fields = ('order_id', 'address', 'pay_method')
        read_only_fields = ('order_id',)
        extra_kwargs = {
            'address': {
                'write_only': True,
                'required': True,
            },
            'pay_method': {
                'write_only': True,
                'required': True
            }
        }

    def create(self, validated_data):
        """保存订单"""
        # 获取当前保存订单时需要的信息
        # 获取当前下单用户
        user = self.context['request'].user
        # 生成订单编号
        order_id = timezone.now().strftime('%Y%m%d%H%M%S') + ('%09d' % user.id)
        # 获取校验之后的地址和支付方式
        address = validated_data.get('address')
        pay_method = validated_data.get('pay_method')

        # 定义事务
        with transaction.atomic():
            # 创建事件保存点
            save_id = transaction.savepoint()
            try:
                # 保存订单基本信息 OrderInfo(⼀一)
                order = OrderInfo.objects.create(
                    order_id=order_id,  # 订单编号
                    user=user,  # 下单用户
                    address=address,  # 地址
                    total_count=0,  # 商品总数
                    total_amount=Decimal('0'),  # 商品总金额
                    freight=Decimal('10.00'),  # 运费
                    pay_method=pay_method,  # 支付方式
                    # 如果是支付宝支持当前状态就是未支付,如果是货到付款就是待发货状态
                    status=OrderInfo.ORDER_STATUS_ENUM['UNPAID'] if pay_method == OrderInfo.PAY_METHODS_ENUM[
                        'ALIPAY'] else
                    OrderInfo.ORDER_STATUS_ENUM['UNSEND']  # 订单状态
                )
                # 从redis读取购物⻋车中被勾选的商品信息
                redis_conn = get_redis_connection('cart')
                redis_cart = redis_conn.hgetall('cart_%s' % user.id)
                selected = redis_conn.smembers('selected_%s' % user.id)
                # 将被勾选的购物车商品筛选出来
                carts = {}
                for sku_id in selected:
                    carts[int(sku_id)] = int(redis_cart[sku_id])
                # 先查询出所有商品的sku_id,再去实时查询库存
                sku_ids = carts.keys()

                # 遍历购物⻋车中被勾选的商品信息
                for sku_id in sku_ids:
                    while True:
                        # 获取sku对象
                        sku = SKU.objects.get(id=sku_id)

                        # 读取原始库存
                        origin_stock = sku.stock  # 库存
                        origin_sales = sku.sales  # 销量
                        sku_count = carts[sku.id]  # 获取购买数量
                        # 判断库存
                        if sku_count > origin_stock:
                            # 库存不足,回滚
                            transaction.savepoint_rollback(save_id)
                            raise serializers.ValidationError('库存不足')


                        # # 减少库存，增加销量量 SKU(实例)
                        # sku.stock -= sku_count  # 减少库存
                        # sku.sales += sku_count  # 增加销量
                        # sku.save()  # 保存到数据库

                        # 更新库存
                        new_stock = origin_stock - sku_count
                        new_sales = origin_sales + sku_count
                        # 乐观锁更新库存
                        result = SKU.objects.filter(id=sku_id, stock=origin_stock).update(stock=new_stock, sales=new_sales)

                        # 如果下单失败,但是库存足够时,继续下单,只到下单成功或者库存确实不足就停止
                        if result == 0:
                            continue

                        # 修改SPU(类)销量量
                        sku.goods.sales += sku_count
                        sku.goods.save()

                        # 保存订单商品信息 OrderGoods(多)
                        OrderGoods.objects.create(
                            order=order,  # 订单
                            sku=sku,  # 商品
                            count=sku_count,  # 商品数量
                            price=sku.price,  # 商品价格
                        )
                        # 保存商品订单中总价和总数量
                        order.total_count += sku_count  # 总数量
                        order.total_amount += (sku_count * sku.price)

                        # 下单成功后或者库存确实不足时,停止死循环
                        break
                # 总价加入邮费
                order.total_amount += order.freight
                # 保存商品订单
                order.save()
            except serializers.ValidationError:
                # 前面已经回滚了
                raise
            except Exception:
                transaction.savepoint_rollback(save_id)
                raise
            # 提交事务
            transaction.savepoint_commit(save_id)
        # 清除购物⻋车中已结算的商品
        pl = redis_conn.pipeline()
        pl.hdel('cart_%s' % user.id, *selected)
        pl.srem('selected_%s' % user.id, *selected)
        pl.execute()
        # 保存完成
        return order


class CartSKUSerializer(serializers.ModelSerializer):
    """
    购物车商品数据序列化器
    """
    count = serializers.IntegerField(label='数量')

    class Meta:
        model = SKU
        fields = ('id', 'name', 'default_image_url', 'price', 'count')


class OrderSettlementSerializer(serializers.Serializer):
    """
    订单结算数据序列化器
    """
    freight = serializers.DecimalField(label='运费', max_digits=10, decimal_places=2)
    skus = CartSKUSerializer(many=True)
